<!--
 * @Description: 
 * @Author: qingyang
 * @Date: 2022-09-09 13:50:54
 * @LastEditors: chenju
 * @LastEditTime: 2023-02-16 10:58:42
-->
<template>
  <CDialog
    :title="title"
    size="small"
    v-model:visible="dialogVisible"
    @confirm="confirmClick"
    @cancel="dialogVisible = false"
    :loading="loading"
  >
    <el-form
      ref="formRef"
      style="width: 100%"
      :model="taskForm"
      :rules="obj.rules"
      label-position="top"
    >
      <el-row>
        <el-col :span="24">
          <el-form-item label="角色名称" prop="roleName">
            <el-input
              :disabled="props.readonly"
              v-model="taskForm.roleName"
              placeholder="请输入角色名称"
            />
          </el-form-item>
        </el-col>
        <el-col :span="24">
          <el-form-item label="角色描述" prop="roleDesc">
            <el-input
              type="textarea"
              :disabled="props.readonly"
              v-model="taskForm.roleDesc"
              maxlength="255"
              show-word-limit
              resize="none"
              placeholder="请输入角色描述"
            />
          </el-form-item>
        </el-col>
        <el-col :span="24">
          <el-form-item label="权限设置" prop="menuIds">
            <el-tree-select
              class="tree"
              ref="treeRef"
              highlight-current
              v-model="taskForm.menuIds"
              :disabled="props.readonly"
              node-key="id"
              :data="treeData"
              multiple
              :render-after-expand="false"
              show-checkbox
              :check-strictly="false"
              :collapse-tags="!props.readonly"
              :defaultExpandedKeys="defaultExpandedKeys"
            />
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <!-- <div class="set-auth-role-container g-flex">
      <div class="set-auth-role-left g-pt4">
        <div
          class="role-scope g-flex-start-center"
          :class="activeScope?.id === scopeItem.id ? 'scope-active' : ''"
          v-for="scopeItem in scopeList"
          :key="scopeItem.id"
          @click="handleChangeScope(scopeItem)"
        >
          <span>{{ scopeItem.name }}</span>
        </div>
      </div>
      <div class="set-auth-role-right g-flex-1">
        <RoleTree
          :scopeItem="activeScope"
          ref="roleTreeRef"
          :menuList="menuList"
          @onSetRootMenu="handleSetRootMenu"
          :readonly="props.readonly"
        ></RoleTree>
      </div>
    </div> -->
    <template #footer v-if="props.readonly">
      <span></span>
    </template>
  </CDialog>
</template>
<script lang="ts">
export default {
  name: 'SetAuthDialog'
};
</script>
<script lang="ts" setup>
import {
  defineProps,
  withDefaults,
  defineEmits,
  computed,
  ref,
  watch,
  nextTick,
  reactive
} from 'vue';
import { CDialog } from '@/components/CDialog';
import { useMessage } from '@/hooks/useMessage';
import { updateRoleMenu, getMenuTree, getMenuIds } from '@/apis/system/role';
import type { GetMenuTreeResult } from '@/apis/system/model/roleModel';
import RoleTree from './RoleTree/index.vue';
import type { MenuListItem, ScopeItem } from './types';
import { cloneDeep } from 'lodash';
import * as obj from './rules';
import { createRole, updateRole } from '@/apis/system/role';

interface SelectFillTypeDialogProps {
  visible: boolean;
  data?: any;
  readonly: boolean;
}
const props = withDefaults(defineProps<SelectFillTypeDialogProps>(), {
  readonly: false
});
const emit = defineEmits(['update:visible', 'refresh']);
const treeData = ref<any[]>([]);
const treeRef = ref();
const dialogVisible = computed<boolean>({
  get: () => {
    return props.visible;
  },
  set: val => {
    emit('update:visible', val);
  }
});
const title = computed(() => {
  if (props.data) {
    return '编辑角色';
  } else {
    return '新增角色';
  }
});
const formRef = ref();

watch(
  () => dialogVisible.value,
  visible => {
    if (visible) {
      init();
    } else {
      formRef.value?.resetFields();
    }
  }
);

const { createMessage } = useMessage();
const loading = ref(false);
const menuList = ref<MenuListItem[]>([]);
let taskForm = reactive({
  roleName: '',
  roleDesc: '',
  menuIds: [] as number[]
});

const defaultExpandedKeys = ref<number[]>([]);
async function init() {
  loading.value = true;
  taskForm.roleName = '';
  taskForm.roleDesc = '';
  taskForm.menuIds = [];
  let roleId = props.data?.id || '';
  let params_menu = {
    roleId: roleId
  };
  try {
    const res = await getMenuTree(params_menu);
    // 默认展开第一级
    defaultExpandedKeys.value = res.map(item => item.id);
    treeData.value = res;
    // 以下代码为RoleTree使用
    // scopeList.value = handleMenuTreeInit(res);
    // activeScope.value = scopeList.value[0];
    // menuList.value = activeScope.value.children;
    // nextTick(() => {
    //   roleTreeRef.value?.collapseOpenAll();
    // });
    if (props.data) {
      taskForm.roleName = props.data.roleName;
      taskForm.roleDesc = props.data.roleDesc;
      taskForm.menuIds = getChildMenus(res);
    }
  } finally {
    loading.value = false;
  }
}

const confirmClick = () => {
  formRef.value?.validate((valid: boolean) => {
    if (valid) {
      saveRole();
    }
  });
};

const saveRole = () => {
  // const ids = getCheckedMenuIds();
  loading.value = true;
  const checkedMenuIds = treeRef.value.getCheckedKeys();
  const halfCheckedMenuIds = treeRef.value.getHalfCheckedKeys();
  const menuIds = [...new Set([...checkedMenuIds, ...halfCheckedMenuIds])];
  // 接口待测试
  if (props.data) {
    const params = { ...taskForm, roleId: props.data.id, menuIds };
    updateRole(params)
      .then((res: any) => {
        createMessage.success('编辑角色成功');
        dialogVisible.value = false;
        emit('refresh');
      })
      .finally(() => {
        loading.value = false;
      });
  } else {
    createRole({ ...taskForm, menuIds })
      .then((res: any) => {
        createMessage.success('新增角色成功');
        dialogVisible.value = false;
        emit('refresh');
      })
      .finally(() => {
        loading.value = false;
      });
  }
};

const getChildMenus = (menus: GetMenuTreeResult[]) => {
  // 获取子的所有menus
  let ids: number[] = [];
  function filterMenus(menus: GetMenuTreeResult[]) {
    for (let i = 0; i < menus.length; i++) {
      if (menus[i].enable) {
        if (!menus[i].children) {
          ids.push(menus[i].id);
        } else {
          filterMenus(menus[i].children as GetMenuTreeResult[]);
        }
      }
    }
  }
  filterMenus(menus);
  return ids;
};

// 获取菜单id
function getCheckedMenuIds() {
  let checkedIds: number[] = [];
  for (let i in scopeList.value) {
    const scopeItem = scopeList.value[i];
    console.log('scopeItem', scopeItem);
    let ids = roleTreeRef.value?.getCheckedOrIndeterminateMenuId(scopeItem.children);
    // NOTE 需要把一级菜单加进入
    if (ids?.length) ids = [...ids, scopeItem.id];
    checkedIds = [...checkedIds, ...ids];
  }
  return checkedIds;
}

// 处理菜单树
function handleMenuTreeInit(menuRes: GetMenuTreeResult[]): ScopeItem[] {
  const menuList = cloneDeep(menuRes);
  for (let n = 0; n < menuList.length; n++) {
    const scopeRoles: number[] = [];
    const scopeIndeterminate: number[] = [];
    const scopeCheckedRoles: number[] = [];
    const scopeItem = menuList[n];
    if (scopeItem.children?.length) {
      for (let i = 0; i < scopeItem.children.length; i++) {
        const itemI = scopeItem.children[i];
        const permission: number[] = [];
        const allPermission: number[] = [];
        if (itemI.children?.length) {
          for (let j = 0; j < itemI.children.length; j++) {
            const itemJ = itemI.children[j];
            if (itemJ.type === '1') {
              allPermission.push(itemJ.id);
              if (itemJ.enable) {
                permission.push(itemJ.id);
                Object.assign(itemJ, {
                  checkStatus: true
                });
              } else {
                Object.assign(itemJ, {
                  checkStatus: false
                });
              }
            }
            if (itemJ.children?.length) {
              for (let k = 0; k < itemJ.children.length; k++) {
                const itemK = itemJ.children[k];
                if (itemK.type === '1') {
                  allPermission.push(itemK.id);
                  if (itemK.enable) {
                    permission.push(itemK.id);
                    Object.assign(itemK, {
                      checkStatus: true
                    });
                  } else {
                    Object.assign(itemK, {
                      checkStatus: false
                    });
                  }
                }
              }
            }
          }
        }
        Object.assign(itemI, {
          checkedRoles: permission
        });
        scopeRoles.push(itemI.id);
        if (permission.length && permission.length < allPermission.length) {
          Object.assign(itemI, {
            checkStatus: false,
            isIndeterminate: true
          });
          scopeIndeterminate.push(itemI.id);
        } else if (permission.length && permission.length === allPermission.length) {
          Object.assign(itemI, {
            checkStatus: true,
            isIndeterminate: false
          });
          scopeCheckedRoles.push(itemI.id);
        } else {
          Object.assign(itemI, {
            checkStatus: false,
            isIndeterminate: false
          });
        }
      }

      Object.assign(scopeItem, {
        checkStatus: true
      });
    }
    updateActiveScope(scopeRoles, scopeCheckedRoles, scopeIndeterminate, scopeItem);
  }

  console.log('handleMenuTreeInit', menuList);

  return menuList as ScopeItem[];
}

// 更新activescope的选中状态
function updateActiveScope(
  scopeRoles: number[],
  scopeCheckedRoles: number[],
  scopeIndeterminate: number[],
  scopeItem: GetMenuTreeResult
) {
  console.log('updateActiveScope', scopeItem);
  Object.assign(scopeItem, {
    allCheckRoles: scopeRoles,
    checkedRoles: scopeCheckedRoles,
    indeterminateRoles: scopeIndeterminate
  });
  if (scopeIndeterminate.length) {
    Object.assign(scopeItem, {
      checkStatus: false,
      isIndeterminate: true
    });
  } else if (scopeCheckedRoles.length && scopeCheckedRoles.length === scopeRoles.length) {
    Object.assign(scopeItem, {
      checkStatus: true,
      isIndeterminate: false
    });
  } else if (scopeCheckedRoles.length && scopeCheckedRoles.length < scopeRoles.length) {
    Object.assign(scopeItem, {
      checkStatus: false,
      isIndeterminate: true
    });
  } else {
    Object.assign(scopeItem, {
      checkStatus: false,
      isIndeterminate: false
    });
  }
}

// 重新渲染activeScope
function rerenderActiveScope() {
  if (activeScope.value) {
    activeScope.value.checkedRoles = [...new Set(activeScope.value.checkedRoles)];
    activeScope.value.indeterminateRoles = [...new Set(activeScope.value.indeterminateRoles)];
    if (activeScope.value.indeterminateRoles.length) {
      activeScope.value.checkStatus = false;
      activeScope.value.isIndeterminate = true;
    } else if (
      activeScope.value.checkedRoles.length &&
      activeScope.value.checkedRoles.length === activeScope.value.allCheckRoles.length
    ) {
      activeScope.value.checkStatus = true;
      activeScope.value.isIndeterminate = false;
    } else if (
      activeScope.value.checkedRoles.length &&
      activeScope.value.checkedRoles.length < activeScope.value.allCheckRoles.length
    ) {
      activeScope.value.checkStatus = false;
      activeScope.value.isIndeterminate = true;
    } else {
      activeScope.value.checkStatus = false;
      activeScope.value.isIndeterminate = false;
    }
  }
}

// 右侧树ref实例
const roleTreeRef = ref();
// scope列表
const scopeList = ref<ScopeItem[]>([]);
// 当前激活的scope
const activeScope = ref<ScopeItem>();
// scope节点全选操作
function handleCheckAllChangeScope(val: boolean, scope: ScopeItem) {
  console.log('handleCheckAllChangeScope', val, scope);
  scope.isIndeterminate = false;
  if (scope.id === activeScope.value?.id) {
    if (val) {
      for (let i in menuList.value) {
        const item = menuList.value[i];
        roleTreeRef.value?.handleCheckAllChange(true, item, false);
      }
    } else {
      for (let i in menuList.value) {
        const item = menuList.value[i];
        roleTreeRef.value?.handleCheckAllChange(false, item, false);
      }
    }
  } else {
    const menuList = scope.children;
    console.log('handleCheckAllChangeScope menuList', val, menuList);
    for (let i in menuList) {
      const item = menuList[i];
      roleTreeRef.value?.handleCheckAllChange(val, item, false);
    }
  }
}
// 添加已选
function addCheckedRoles(id: number, index: number) {
  if (index < 0) {
    activeScope.value!.checkedRoles.push(id);
  }
}
// 删除已选
function removeCheckedRoles(index: number) {
  if (index > -1) {
    activeScope.value!.checkedRoles.splice(index, 1);
  }
}
// 添加半选
function addIndeterminateRoles(id: number, index: number) {
  if (index < 0) {
    activeScope.value!.indeterminateRoles.push(id);
  }
}
// 删除半选
function removeIndeterminateRoles(index: number) {
  if (index > -1) {
    activeScope.value!.indeterminateRoles.splice(index, 1);
  }
}
// 发起更新scope状态
function handleSetRootMenu(menu: MenuListItem) {
  console.log('handleSetRootMenu', menu, activeScope.value);
  const checkedIndex = activeScope.value!.checkedRoles.findIndex(n => n === menu.id);
  const indeterminateIndex = activeScope.value!.indeterminateRoles.findIndex(n => n === menu.id);
  if (menu.checkStatus === true) {
    // 添加已选
    addCheckedRoles(menu.id, checkedIndex);
    // 删除半选
    removeIndeterminateRoles(indeterminateIndex);
  } else if (menu.isIndeterminate === true) {
    // 添加半选
    addIndeterminateRoles(menu.id, indeterminateIndex);
    // 删除已选
    removeCheckedRoles(checkedIndex);
  } else {
    // 删除已选
    removeCheckedRoles(checkedIndex);
    // 删除半选
    removeIndeterminateRoles(indeterminateIndex);
  }

  rerenderActiveScope();
}
// 手动选择scope
function handleChangeScope(scope: ScopeItem) {
  console.log('handleChangeScope', scope, activeScope.value);
  if (scope.id === activeScope.value!.id) return;
  activeScope.value = scope;
  menuList.value = activeScope.value.children;
  nextTick(() => {
    roleTreeRef.value?.collapseOpenAll();
  });
}
</script>

<style lang="scss" scoped>
.set-auth-contianer {
  margin: 0 !important;
  height: 60vh;
  overflow: hidden;
  .set-auth-title {
    height: 30px;
  }
  .set-auth-role-container-checkbox-group {
    height: 100%;
  }
  .set-auth-role-container {
    width: 100%;
    height: calc(100% - 78px);
    background: #f8fbfc;
    border-radius: 4px;
    border: 1px solid #ebeff2;
    font-size: 14px;
    font-weight: 400;
    color: #212529;
    .set-auth-role-left {
      width: 140px;
      height: 100%;
      border-right: 1px solid #ebeff2;
      .role-scope {
        position: relative;
        padding-left: 20px;
        height: 36px;
        cursor: pointer;
        &::after {
          position: absolute;
          top: 0;
          left: 0;
          bottom: 0;
          border-right: 2px solid $themeColor;
          transform: scaleY(0.0001);
          opacity: 0;
          transition: transform 0.15s cubic-bezier(0.215, 0.61, 0.355, 1),
            opacity 0.15s cubic-bezier(0.215, 0.61, 0.355, 1);
          content: '';
        }
      }
      .scope-active.role-scope {
        background: #edf2f7;
        &::after {
          transform: scaleY(1);
          opacity: 1;
          transition: transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1),
            opacity 0.15s cubic-bezier(0.645, 0.045, 0.355, 1);
        }
      }
    }
    .set-auth-role-right {
      height: 100%;
      overflow-y: auto;
    }
    // 禁用的checkbox样式修改
    :deep(.el-checkbox__input.is-disabled) {
      &.is-indeterminate,
      &.is-checked {
        .el-checkbox__inner {
          background-color: var(--el-checkbox-checked-bg-color);
          border-color: var(--el-checkbox-checked-input-border-color);
        }
      }
    }
  }
}
:deep(.el-select--disabled.tree) {
  .el-input__suffix {
    display: none;
  }
}
</style>
